﻿
#region Imported Namespaces

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Xml.Serialization;
using System.Xml;
using System.IO;

#endregion

namespace TupleGeo.Emergency.CAP {

  /// <summary>
  /// 
  /// </summary>
  /// <typeparam name="T"></typeparam>
  public partial class EntityBase<T> : INotifyPropertyChanged {

    #region Member Variables

    /// <summary>
    /// Event to indicate that a property value has been changed.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    #endregion

    #region Public Properties

    private static XmlSerializer _serializer;

    /// <summary>
    /// 
    /// </summary>
    private static XmlSerializer Serializer {
      get {
        if ((_serializer == null)) {
          _serializer = new XmlSerializer(typeof(T));
        }
        return _serializer;
      }
    }

    #endregion

    #region Public Methods


    /// <summary>
    /// Raises the <see cref="PropertyChangedEventHandler">PropertyChanged</see> event.
    /// </summary>
    /// <param name="propertyName">
    /// The name of the property whose value has been changed.
    /// </param>
    public virtual void OnPropertyChanged(string propertyName) {
      PropertyChangedEventHandler handler = this.PropertyChanged;
      if ((handler != null)) {
        handler(this, new PropertyChangedEventArgs(propertyName));
      }
    }

    /// <summary>
    /// Serializes current EntityBase object into an XML document
    /// </summary>
    /// <returns>string XML value</returns>
    public virtual string Serialize(Encoding encoding) {
      StreamReader streamReader = null;
      MemoryStream memoryStream = null;
      try {
        memoryStream = new MemoryStream();
        XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
        xmlWriterSettings.Encoding = encoding;
        XmlWriter xmlWriter = XmlWriter.Create(memoryStream, xmlWriterSettings);
        Serializer.Serialize(xmlWriter, this);
        memoryStream.Seek(0, SeekOrigin.Begin);
        streamReader = new StreamReader(memoryStream);
        return streamReader.ReadToEnd();
      }
      finally {
        if ((streamReader != null)) {
          streamReader.Dispose();
        }
        if ((memoryStream != null)) {
          memoryStream.Dispose();
        }
      }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    public virtual string Serialize() {
      return Serialize(Encoding.UTF8);
    }


    /// <summary>
    /// Deserializes workflow markup into an EntityBase object
    /// </summary>
    /// <param name="xml">string workflow markup to deserialize</param>
    /// <param name="obj">Output EntityBase object</param>
    /// <param name="exception">output Exception value if deserialize failed</param>
    /// <returns>true if this XmlSerializer can deserialize the object; otherwise, false</returns>
    public static bool Deserialize(string xml, out T obj, out Exception exception) {
      exception = null;
      obj = default(T);
      try {
        obj = Deserialize(xml);
        return true;
      }
      catch (Exception ex) {
        exception = ex;
        return false;
      }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="xml"></param>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static bool Deserialize(string xml, out T obj) {
      Exception exception = null;
      return Deserialize(xml, out obj, out exception);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="xml"></param>
    /// <returns></returns>
    public static T Deserialize(string xml) {
      StringReader stringReader = null;
      try {
        stringReader = new StringReader(xml);
        return ((T)(Serializer.Deserialize(XmlReader.Create(stringReader))));
      }
      finally {
        if ((stringReader != null)) {
          stringReader.Dispose();
        }
      }
    }

    /// <summary>
    /// Serializes current EntityBase object into file
    /// </summary>
    /// <param name="fileName">full path of outupt xml file</param>
    /// <param name="exception">output Exception value if failed</param>
    /// <returns>true if can serialize and save into file; otherwise, false</returns>
    public virtual bool SaveToFile(string fileName, Encoding encoding, out Exception exception) {
      exception = null;
      try {
        SaveToFile(fileName, encoding);
        return true;
      }
      catch (Exception e) {
        exception = e;
        return false;
      }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="fileName"></param>
    /// <param name="exception"></param>
    /// <returns></returns>
    public virtual bool SaveToFile(string fileName, out Exception exception) {
      return SaveToFile(fileName, Encoding.UTF8, out exception);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="fileName"></param>
    public virtual void SaveToFile(string fileName) {
      SaveToFile(fileName, Encoding.UTF8);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="fileName"></param>
    /// <param name="encoding"></param>
    public virtual void SaveToFile(string fileName, Encoding encoding) {
      StreamWriter streamWriter = null;
      try {
        string xmlString = Serialize(encoding);
        streamWriter = new StreamWriter(fileName, false, Encoding.UTF8);
        streamWriter.WriteLine(xmlString);
        streamWriter.Close();
      }
      finally {
        if ((streamWriter != null)) {
          streamWriter.Dispose();
        }
      }
    }

    /// <summary>
    /// Deserializes xml markup from file into an EntityBase object
    /// </summary>
    /// <param name="fileName">string xml file to load and deserialize</param>
    /// <param name="obj">Output EntityBase object</param>
    /// <param name="exception">output Exception value if deserialize failed</param>
    /// <returns>true if this XmlSerializer can deserialize the object; otherwise, false</returns>
    public static bool LoadFromFile(string fileName, Encoding encoding, out T obj, out Exception exception) {
      exception = null;
      obj = default(T);
      try {
        obj = LoadFromFile(fileName, encoding);
        return true;
      }
      catch (Exception ex) {
        exception = ex;
        return false;
      }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="fileName"></param>
    /// <param name="obj"></param>
    /// <param name="exception"></param>
    /// <returns></returns>
    public static bool LoadFromFile(string fileName, out T obj, out Exception exception) {
      return LoadFromFile(fileName, Encoding.UTF8, out obj, out exception);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="fileName"></param>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static bool LoadFromFile(string fileName, out T obj) {
      Exception exception = null;
      return LoadFromFile(fileName, out obj, out exception);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="fileName"></param>
    /// <returns></returns>
    public static T LoadFromFile(string fileName) {
      return LoadFromFile(fileName, Encoding.UTF8);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="fileName"></param>
    /// <param name="encoding"></param>
    /// <returns></returns>
    public static T LoadFromFile(string fileName, Encoding encoding) {
      FileStream file = null;
      StreamReader sr = null;
      try {
        file = new FileStream(fileName, FileMode.Open, FileAccess.Read);
        sr = new StreamReader(file, encoding);
        string xmlString = sr.ReadToEnd();
        sr.Close();
        file.Close();
        return Deserialize(xmlString);
      }
      finally {
        if ((file != null)) {
          file.Dispose();
        }
        if ((sr != null)) {
          sr.Dispose();
        }
      }
    }

    #endregion

  }

}
